#pragma once
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <vector>
#include <assert.h>
#include <gl/glew.h>
#include <gl/freeglut.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> 

using namespace std;

class Shader
{
public:

	Shader();
	void TakeDown();
	void Use();
	void InitializeADS(char * vertex_shader_file, char * fragment_shader_file);
	bool Initialize(char * vertex_shader_file, char * fragment_shader_file, bool dm);

	GLuint vertex_shader_id;
	GLuint fragment_shader_id;
	GLuint program_id;
	GLuint dm_id;
	GLuint projection_matrix_handle;
	GLuint modelview_matrix_handle;
	GLuint normal_matrix_handle;
	GLuint mvp_handle;
	GLuint source_handlex;
	GLuint source_handley;
	GLuint destination_handlex;
	GLuint destination_handley;
	GLuint displacement_map_handle;
	GLuint window_width_handle;
	GLuint window_height_handle;

	bool LoadShader(const char * file_name, GLuint shader_id);
	stringstream GetShaderLog(GLuint shader_id);

};

class ADSShader : public Shader
{
public:
	ADSShader();
	virtual bool Initialize(char * vertex_shader_file, char * fragment_shader_file);

	void SetLight(glm::vec4 position, glm::vec3 la, glm::vec3 ld, glm::vec3 ls);
	void SetMaterial(glm::vec3 ka, glm::vec3 kd, glm::vec3 ks, float shininess);

	GLuint position_handle;
	GLuint la_handle;
	GLuint ld_handle;
	GLuint ls_handle;
	GLuint ka_handle;
	GLuint kd_handle;
	GLuint ks_handle;
	GLuint shininess_handle;
	GLuint normal_map_handle;
	GLuint texture_map_handle;
	GLuint do_normal_mapping_handle;
	GLuint do_texture_mapping_handle;
	GLuint do_displacement_mapping;

};

class DMShader: public Shader
{
public:
	DMShader();
	virtual bool Initialize(char * vertex_shader_file, char * fragment_shader_file);

	GLuint texture_map_handle;
};